#ifndef __TM16XX_H__
#define __TM16XX_H__

#include <stdint.h>
#include <stdbool.h>

#include <tm16xx_cfg.h>

/**
 * @brief TM16XX驱动芯片枚举类型定义
 * @attention 顺序与@s_gramsize @s_kramsize强相对应，强烈建议不要调整
 */
typedef enum
{
    TM1629D = 0, /*  */
    TM1617,      /*  */
    TM1638,      /*  */
} tm16xx_chiptype_t;

/**
 * @brief 地址增加模式枚举类型定义
 *
 */
typedef enum
{
    ModeAddressIncrease = 0, /* 地址自增模式 */
    ModeFixedAddress         /* 固定地址模式 */
} tm16xx_addrssmode_t;

/**
 * @brief 显示模式枚举类型定义
 * @note 目前只有TM1617需要设定
 */
typedef enum
{
    Mode2Digit8Segment = 0, /* 2位8段模式 */
    Mode3Digit7Segment,     /* 3位7段模式 */
} tm16xx_displaymode_t;

/**
 * @brief 显示辉度等级枚举类型定义
 *
 */
typedef enum
{
    Brightness1_16 = 0, /* 设置脉冲宽度为 1/16 */
    Brightness2_16,     /* 设置脉冲宽度为 2/16 */
    Brightness4_16,     /* 设置脉冲宽度为 4/16 */
    Brightness10_16,    /* 设置脉冲宽度为 10/16 */
    Brightness11_16,    /* 设置脉冲宽度为 11/16 */
    Brightness12_16,    /* 设置脉冲宽度为 12/16 */
    Brightness13_16,    /* 设置脉冲宽度为 13/16 */
    Brightness14_16,    /* 设置脉冲宽度为 14/16 */
} tm16xx_brightness_t;

/**
 * @brief 开关显示枚举类型定义
 *
 */
typedef enum
{
    DisplayOff = 0, /* 关闭显示 */
    DisplayOn       /* 打开显示 */
} tm16xx_displayonoff_t;
/**
 * @brief 片选枚举类型定义
 *
 */
typedef enum
{
    ChipDisable = 0, /* 片选失能 */
    ChipEnable       /* 片选使能 */
} tm16xx_chipselect_t;

/**
 * @brief 命令枚举类型定义
 *
 */
typedef enum
{
#if TM_USE_MSB
    Cmd2Digit8Segment = 0x00,  /* 2位8段 TM1617 */
    Cmd3Digit7Segment = 0xC0,  /* 3位7段 TM1617 */
    CmdAddressIncrease = 0x02, /* 自动地址增加 */
    CmdReadKey = 0x42,         /* 读键扫数据 */
    CmdFixedAddress = 0x22,    /* 固定地址 */
    CmdDisplay = 0x01,         /*  */
#else
    Cmd2Digit8Segment = 0x00,  /* 2位8段 TM1617 */
    Cmd3Digit7Segment = 0x03,  /* 3位7段 TM1617 */
    CmdAddressIncrease = 0x40, /* 自动地址增加 */
    CmdReadKey = 0x42,         /* 读键扫数据 */
    CmdFixedAddress = 0x44,    /* 固定地址 */
    CmdDisplay = 0x80,         /*  */
#endif
} tm16xx_command_t;

typedef enum
{
    tm16xx_dio_input = 0,
    tm16xx_dio_output
} tm16xx_dio_dirction_t;

/**
 * @brief TM16XX接口驱动结构体定义
 *
 */
typedef struct
{
    void (*dlyus)(uint32_t);               /* 微秒延时函数 */
    void (*wrste)(tm16xx_chipselect_t);    /* 片选控制函数 */
    void (*wrsck)(bool);                   /* 时钟控制函数 */
    void (*wrdio)(bool);                   /* 数据控制函数 */
    bool (*rddio)(void);                   /* 读取数据函数 */
} tm16xx_io_t;
/**
 * @brief TM16XX句柄结构体定义
 *
 */
#pragma anon_unions
typedef struct
{
    union
    {
        uint32_t var; /* 模式/状态字 */
        struct
        {
            tm16xx_displayonoff_t displayonoff : 1; /* 显示开关 */
            tm16xx_brightness_t brightness : 3;     /* 显示灰度 */
            uint32_t inited : 1;                    /* 模块初始化完成标志 */
            uint32_t reserved : 2;                  /* 保留 */
            uint32_t ioinited : 1;                  /* io驱动初始化完成 */
            tm16xx_chiptype_t chiptype : 4;         /* 驱动芯片类型 */
            tm16xx_addrssmode_t addressmode : 4;    /* 地址增加模式 */
            tm16xx_displaymode_t displaymode : 4;   /* 显示模式 */
            uint32_t bitdelay : 4;                  /* 数据位等待时间 单位us */
            uint32_t ackdelay : 4;                  /* 读按键等待时间 单位us */
            uint32_t cmddelay : 4;                  /* 命令间延时时间 单位us */
        };
    };
    tm16xx_io_t io;    /* 接口驱动 */
    uint8_t addr[16];  /* 显存地址表 */
    uint8_t uaddr[16]; /* 逻辑地址表 */
    uint8_t gram[16];  /* 显示缓冲区 */
    uint8_t kram[8];   /* 键值缓冲区 */
} tm16xx_t;

int32_t tm16xx_init_default(tm16xx_t *p);
int32_t tm16xx_register(tm16xx_t *p, tm16xx_io_t *pio);
int32_t tm16xx_flushall(tm16xx_t *p, uint8_t *dbuf, uint8_t dlen, uint8_t *kbuf, uint8_t klen);
int32_t tm16xx_write(tm16xx_t *p, uint8_t *dbuf, uint8_t len);
int32_t tm16xx_read(tm16xx_t *p, uint8_t *buf, uint8_t len);
int32_t tm16xx_set_useraddr(tm16xx_t *p, uint8_t *abuf, uint8_t len);
int32_t tm16xx_set_displaymode(tm16xx_t *p, tm16xx_displaymode_t displaymode);
int32_t tm16xx_set_brightness(tm16xx_t *p, tm16xx_brightness_t brightness);
int32_t tm16xx_set_displayonoff(tm16xx_t *p, tm16xx_displayonoff_t displayonoff);
int32_t tm16xx_set_addressmode(tm16xx_t *p, tm16xx_addrssmode_t addressmode);
int32_t tm16xx_set_chiptype(tm16xx_t *p, tm16xx_chiptype_t chiptype);

int32_t display_format_string(char *c, uint8_t *buf, uint8_t len);
int32_t display_format_hex(uint32_t v, uint8_t *buf, uint8_t len);
int32_t display_format_dec(int32_t v, uint8_t *buf, uint8_t len);
/*
demo

#define BIT_BAND(addr,bit)   *(volatile unsigned long*)(((uint32_t)(addr) & 0xF0000000) +\
                0x2000000 + (((uint32_t)(addr) & 0xFFFFF)<<5) + ((bit)<<2))

static void delay_us(uint32_t l)
{
    while (l--)
    {
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
    }
}
static void tm16_wrste(tm16xx_chipselect_t s)
{
    BIT_BAND(&GPIOE->ODR, 2) = (ChipEnable == s) ? 0:1;
}
static void tm16_wrsck(bool s)
{
    BIT_BAND(&GPIOE->ODR, 3) = s;
}
static void tm16_wrdio(bool s)
{
    BIT_BAND(&GPIOE->ODR, 4) = s;
}
static bool tm16_rddio(void)
{
    return BIT_BAND(&GPIOE->IDR, 4);
}

void main()
{
    uint8_t gram[16];
    uint8_t kram[1];
    tm16xx_init_default(&tm1629d);
    tm16xx_set_addressmode(&tm1629d, ModeFixedAddress);

    //固定地址模式 根据硬件原理选用逻辑地址
    // 对于1629D 和 1638 为16个地址
    // 显存地址: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
    // 逻辑地址:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

    // 对于1617 仅6个地址
    // 显存地址: C0 C1 C2 C3 XX XX XX XX XX XX XX XX CC CD
    // 逻辑地址:  0  1  2  3  4  5  6  7  8  9 10 11 12 13
    if (tm1629d.addressmode == ModeFixedAddress)
    {
        // tm1629d 显存地址为16个，此处选用第0,2,4,6,8,10共6个地址.
        // 使用6位共阴数码管，段码接SEG1~8 ,位码接GRID1~5, 配置如下:
        uint8_t a[6] = {0, 2, 4, 6, 8, 10};
        tm16xx_set_useraddr(&tm1629d, a, 6);


        //对于1617使用3位7段模式逻辑地址配置如下
        // uint8_t a[6] = {0, 1, 2, 3, 12, 13};
        // tm16xx_set_useraddr(&tm1617, a, 6);
    }
    //地址自增模式需配置首地址
    else
    {
        // 首地址配置逻辑地址0 即从显存地址C0开始
        uint8_t a[1] = {0};
        tm16xx_set_useraddr(&tm1629d, a, 1);

        // 首地址配置逻辑地址4  即从显存地址C4开始
        // uint8_t a[1] = {4};
        // tm16xx_set_useraddr(&tm1638, a, 1);

        // 首地址配置逻辑地址4  即从显存地址CC开始
        // uint8_t a[1] = {12};
        // tm16xx_set_useraddr(&tm1617, a, 1);
    }
    //注册硬件接口驱动
    {
        tm16xx_io_t tm1629d_io={
            .dlyus = delay_us,
            .wrste = tm16_wrste,
            .wrsck = tm16_wrsck,
            .wrdio = tm16_wrdio,
            .rddio = tm16_rddio
        };
        tm16xx_register(&tm1629d, &tm1629d_io);
    }
    while(1)
    {
        if (tm1629d.addressmode == ModeFixedAddress)
        {
            if ((gram[4] == 0) || (gram[4] == 0x80))
                gram[4] = 1;
            else
                gram[4] <<= 1;
            gram[0] = kram[0];
            gram[1] = gram[2] = gram[3] = gram[4];
        }
        else
        {
            gram[0] = gram[2] = gram[4] = gram[6] = kram[0];
            if ((gram[8] == 0) || (gram[8] == 0x80))
                gram[8] = 1;
            else
                gram[8] <<= 1;
        }
        tm16xx_flushall(&tm1629d, gram, 5, kram, sizeof(kram));
    }
}
int32_t tm16xx_common_anode(uint8_t*src,uint8_t*dst, uint8_t len)
{
    struct bitbyte
    {
        unsigned char b0:1;
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char b5:1;
        unsigned char b6:1;
        unsigned char b7:1;
    };
    struct bitbyte *ps = (struct bitbyte *)&src[0];
    struct bitbyte *pd = (struct bitbyte *)&dst[0];
    #define BITDS(x,y) pd->b##x = ps[7-x].b##y
    #define BYTEDS(n) BITDS(0,n);BITDS(1,n);BITDS(2,n);BITDS(3,n);BITDS(4,n);BITDS(5,n);BITDS(6,n);BITDS(7,n);pd+=2
    if(len == 16)
    {
        BYTEDS(0);
        BYTEDS(1);
        BYTEDS(2);
        BYTEDS(3);
        BYTEDS(4);
        BYTEDS(5);
        BYTEDS(6);
        BYTEDS(7);
        ps+=8;
        pd = (struct bitbyte *)&dst[1];
t8:
        BYTEDS(0);
        BYTEDS(1);
        BYTEDS(2);
        BYTEDS(3);
        BYTEDS(4);
        BYTEDS(5);
        BYTEDS(6);
        BYTEDS(7);
        return 0;
    }
    else if(len==8)
    {
        goto t8;
    }
    else
    {
        return -1;
    }
}
*/
#endif
